;;; guile-semver --- Semantic Version tooling for guile
;;; Copyright © 2017 Jelle Dirk Licht <jlicht@fsfe.org>
;;;
;;; This file is part of guile-semver.
;;;
;;; guile-semver is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or
;;; (at your option) any later version.
;;;
;;; guile-semver is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with guile-semver.  If not, see <http://www.gnu.org/licenses/>.

(define-module (test-semver)
  #:use-module (semver parser)
  #:use-module (semver)
  #:use-module (semver parser-range)
  #:use-module (semver matcher)
  #:use-module (semver comparator)
  #:use-module (semver structs)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-64))

(test-begin "invalid semver")
(every (lambda (spec)
	 (let ((msg (string-append
		     "Invalid semver should not parse: "
		     (object->string spec))))
	   (test-assert msg (equal? (parse-semver spec) #f))))
       '(""
	 "=1.2.3"
	 "v0.9.2"
	 "a.b.0"
	 ;; "7.4.1-"
	 "4.3.-"
	 ;; "4.3.3-023.adsf"
	 ;; "5.0.7+"
	 ;; "2.2.3+build-alsobuild"
	 ))
(test-end "invalid semver")

(test-begin "valid semver")
(every (lambda (spec)
	 (let ((msg (string-append
		     "Valid semver should parse: "
		     (object->string spec))))
	   (test-assert msg (valid? spec))))
       '("1.2.3"
	 "0.9.2"
	 "9.8.7"
	 "0.8.7-pre"
	 "0.8.0-beta.3"
	 "0.8.7-pre-release-identifier-is-long"
	 "8.2.1-pre.with.0.working"
	 "8.2.1-pre.with.7.working"
	 "2.8.4+32"
	 "2.8.4+git.build.23232"
	 "0.8.0-beta.3+ci.generated"
         ))
(test-end "valid semver")


(test-begin "inc semver")
(every (lambda (spec)
	 (let ((msg (string-append
		     "Incremented semver" " should e: "
		     (object->string spec))))
	   (test-assert msg (parse-semver spec))))
       '("1.2.3"
	 "0.9.2"
	 "9.8.7"
	 "0.8.7-pre"
	 "0.8.0-beta.3"
	 "0.8.7-pre-release-identifier-is-long"
	 "8.2.1-pre.with.0.working"
	 "8.2.1-pre.with.7.working"
	 "2.8.4+32"
	 "2.8.4+git-build-23232"))
(test-end "inc semver")


(test-begin "gt")
(every (lambda (spec)
	 (let ((msg (object->string spec)))
	   (test-assert msg (apply gt spec))))
       '(("1.0.1" "1.0.0")
	 ("0.6.10" "0.6.1")))
(test-end "gt")


(test-begin "in range")
(every (lambda (spec)
	 (let ((msg (object->string spec)))
	   (test-assert msg (apply satisfies (reverse spec)))))
       '(("=1.0.0" "1.0.0")
	 ("~0.6.1" "0.6.1")
         ("1.0.0 - 2.0.0" "1.2.3")
         ("1.0.0" "1.0.0")
         (">=0.0.0" "0.2.4")
         ("X" "1.0.0")
         ("*" "1.2.3")
         ("*" "1.2.3")
         (">=1.0.0" "1.0.0")
         (">=1.0.0" "1.0.1")
         (">=1.0.0" "1.1.0")
         (">1.0.0" "1.0.1")
         (">1.0.0" "1.1.0")
         ("<=2.0.0" "2.0.0")
         ("<=2.0.0" "1.9999.9999")
         ("<=2.0.0" "0.2.9")
         ("<2.0.0" "1.9999.9999")
         ("<2.0.0" "0.2.9")
         (">= 1.0.0" "1.0.0")
         (">=  1.0.0" "1.0.1")
         (">=   1.0.0" "1.1.0")
         ("> 1.0.0" "1.0.1")
         (">  1.0.0" "1.1.0")
         ("<=   2.0.0" "2.0.0")
         ("<= 2.0.0" "1.9999.9999")
         ("<=  2.0.0" "0.2.9")
         ("<    2.0.0" "1.9999.9999")
         ("<\t2.0.0" "0.2.9")
         (">=0.1.97" "0.1.97")
         (">=0.1.97" "0.1.97")
         ("0.1.20 || 1.2.4" "1.2.4")
         ("0.1.20 || >=1.2.4" "1.2.4")
         ("0.1.20 || <1.2.4" "1.2.3")
         ("0.1.20 || 1.2.4" "0.1.20")
         (">=0.2.3 || <0.0.1" "0.0.0")
         (">=0.2.3 || <0.0.1" "0.2.3")
         (">=0.2.3 || <0.0.1" "0.2.4")
         ("x || x" "1.3.4")
         ("2.x.x" "2.1.3")
         ("1.2.x" "1.2.3")
         ("1.2.x || 2.x" "2.1.3")
         ("1.2.x || 2.x" "1.2.3")
         ("x" "1.2.3")
         ("2.*.*" "2.1.3")
         ("1.2.*" "1.2.3")
         ("1.2.* || 2.*" "2.1.3")
         ("1.2.* || 2.*" "1.2.3")
         ("1.2.* || 2.*" "1.2.3")
         ("*" "1.2.3")
         ("2" "2.1.2")
         ("2.3" "2.3.1")
         ("~2.4" "2.4.0")
         ("~2.4" "2.4.5")
         (">3.2.1" "3.2.2")
         ("~1" "1.2.3")
         ("~1" "1.2.3")
         ("~ 1" "1.2.3")
         ("~1.0" "1.0.2")
         ("~ 1.0" "1.0.2")
         (">=1" "1.0.0")
         (">= 1" "1.0.0")
         ("<1.2" "1.1.1")
         ("< 1.2" "1.1.1")
         ("1" "1.0.0")
         ("~0.5.4" "0.5.5")
         ("~0.5.4" "0.5.4")
         ("0.7.x" "0.7.2")
         (">=0.7.0" "0.7.2")
         ("0.7.x" "0.7.0")
         (">=0.7.0" "0.7.0")
         ("<=0.7.0" "0.6.2")
         (">0.2.3 >0.2.4 <=0.2.5" "0.2.5")
         (">=0.2.3 <=0.2.4" "0.2.4")
         ("1.0.0 - 2.0.1" "2.0.0")
         ("^1" "1.0.0")
         ("^0.0.0" "0.0.0")
         ("^1.0.0 || ~2.0.1" "2.0.10")
         ("^0.1.0 || ^3.0 || 5.0.0" "3.1.0")
         ("^0.1.0 || ~3.0.1 || 5.0.0" "5.0.0")
         ("<1.0.0 || <3.0.1 || <5.0.0 || <6.0.0 || 9.0.0" "9.0.0")
	 ("^1.2.x" "1.99.99")
	 (">=1.2.0 <2.0.0" "1.99.99")
	 ("^0.0.x" "0.0.0")
	 ("^0.0.x" "0.0.99")
	 ("^0.0" "0.0.0")
	 ("^0.0" "0.0.99")
	 ("^1.*" "1.0.0")
	 ("^1.*" "1.99.99")))
(test-end "in range")

(test-begin "not in range")
(every (lambda (spec)
	 (let ((msg (object->string spec)))
	   (test-assert msg (not (apply satisfies (reverse spec))))))
       '(("=1.1.0" "1.0.0")
	 ("~1.2.2" "1.3.0")
         ("~0.6.1" "0.7.1")
         ("1.0.0 - 2.0.0" "2.0.1")
         ("1.0.0" "1.0.1")
         ("1.0.0" "2.0.0")
         ("<=2.0.0" "2.1.1")
         ("<=2.0.0" "3.2.9")
         ("<2.0.0" "2.0.0")
         ("0.1.20 || 1.2.4" "1.2.5")
         ("2.x.x" "3.0.0")
         ("1.2.x" "1.3.0")
         ("1.2.x || 2.x" "3.0.0")
         ("2.*.*" "5.0.1")
         ("1.2.*" "1.3.3")
         ("1.2.* || 2.*" "4.0.0")
         ("2" "3.0.0")
         ("2.3" "2.4.2")
         ("~2.4.0" "2.5.0")
         ("~2.4.0" "2.5.5")
         ("~3.2.1" "3.3.0")
         ("~1.0.0" "2.2.3")
         ("~1.0.0" "2.2.4")
         ("~1.0.0" "3.2.3")
         ("~1.0.0" "1.1.2")
         ("~1.0.0" "1.1.0")
         ("<1.2.0" "1.2.0")
         ("<1.2.0" "1.2.1")
         ("1" "2.0.0")
         ("~0.5.4" "0.6.0")
         ("~0.5.4" "0.6.1")
         ("0.7.x" "0.8.0")
         ("<0.7.0" "0.7.0")
         ("~1.2.2" "1.3.0")
         ("1.0.0 - 2.0.0" "2.2.3")
         ("1.0.0" "1.0.1")
         ("<=2.0.0" "3.0.0")
         ("<=2.0.0" "2.9999.9999")
         ("<=2.0.0" "2.2.9")
         ("<2.0.0" "2.9999.9999")
         ("<2.0.0" "2.2.9")
         ("2.x.x" "3.1.3")
         ("1.2.x" "1.3.3")
         ("1.2.x || 2.x" "3.1.3")
         ("2.*.*" "3.1.3")
         ("1.2.*" "1.3.3")
         ("1.2.* || 2.*" "3.1.3")
         ("2" "3.1.2")
         ("2.3" "2.4.1")
         ("~2.4.0" "2.5.0")
         ("~3.2.1" "3.3.2")
         ("~1.0.0" "2.2.3")
         ("~1.0.0" "2.2.3")
         ("~1.0.0" "1.1.0")
         ("<1.0.0" "1.0.0")
         ("1" "2.0.0")
         ("<1.0.0" "1.0.0")
         ("<1.0.0" "1.0.0")
         ("<1.0.0 || <3.0.1 || <5.0.0 || <6.0.0 || >9.1.0" "9.0.0")
         ("<1.0.0  > 10.0 || 5.0" "5.1.0")
         ("0.7.x" "0.8.2")))
(test-end "not in range")

(test-begin "increment semver")
(every (lambda (spec)
	 (let ((msg (string-append
		     "Incremented semver does not match:"
		     (object->string spec))))
	   (test-assert msg (zero? (semantic-version-compare
                                    (inc-semantic-version (parse-semver (car spec)) (cadr spec))
                                    (parse-semver (caddr spec)))))))
       '(("0.0.0" patch "0.0.1")
         ("2.3.4" patch "2.3.5")
         ("9.5.1" minor "9.6.0")
         ("0.4.12+beta" minor "0.5.0")
         ("0.1.12+beta-xorg" major "1.0.0")
         ("2.3.1" major "3.0.0")
         ("1.2.3" premajor "2.0.0-0")
         ("0.1.7" premajor "1.0.0-0")
         ("4.5.6" preminor "4.6.0-0")
         ("9.8.7" preminor "9.9.0-0")
         ("0.5.9" prepatch "0.5.10-0")
         ("5.0.0" prepatch "5.0.1-0")
         ("1.0.0" prerelease "1.0.0-0")
         ("2.0.0-3" prerelease "2.0.0-4")
         ("3.2.1-beta" prerelease "3.2.1-beta.0")
         ("3.2.1-beta.13" prerelease "3.2.1-beta.14")
         ;; premajor 
         ;; preminor
         ;; prepatch
         ;; prerelease
         ))
(test-end "increment semver")
